/*      */ package com.zimbra.cs.mailbox.calendar;
/*      */ 
/*      */ import com.zimbra.common.calendar.ICalTimeZone;
/*      */ import com.zimbra.common.calendar.ParsedDateTime;
/*      */ import com.zimbra.common.calendar.ParsedDuration;
/*      */ import com.zimbra.common.calendar.TimeZoneMap;
/*      */ import com.zimbra.common.calendar.ZCalendar.ICalTok;
/*      */ import com.zimbra.common.calendar.ZWeekDay;
/*      */ import com.zimbra.common.localconfig.DebugConfig;
/*      */ import com.zimbra.common.service.ServiceException;
/*      */ import com.zimbra.common.soap.Element;
/*      */ import com.zimbra.common.util.ListUtil;
/*      */ import com.zimbra.common.util.Log;
/*      */ import com.zimbra.common.util.StringUtil;
/*      */ import com.zimbra.common.util.ZimbraLog;
/*      */ import com.zimbra.cs.mailbox.CalendarItem.Instance;
/*      */ import com.zimbra.cs.mailbox.CalendarItem.Instance.StartTimeComparator;
/*      */ import com.zimbra.cs.mailbox.Metadata;
/*      */ import java.io.PrintStream;
/*      */ import java.text.ParseException;
/*      */ import java.util.ArrayList;
/*      */ import java.util.Calendar;
/*      */ import java.util.Collections;
/*      */ import java.util.Date;
/*      */ import java.util.GregorianCalendar;
/*      */ import java.util.HashMap;
/*      */ import java.util.HashSet;
/*      */ import java.util.Iterator;
/*      */ import java.util.LinkedList;
/*      */ import java.util.List;
/*      */ import java.util.Map;
/*      */ import java.util.Set;
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ public class Recurrence
/*      */ {
/*      */   public static final int TYPE_RECURRENCE = 1;
/*      */   public static final int TYPE_EXCEPTION = 2;
/*      */   public static final int TYPE_CANCELLATION = 3;
/*      */   public static final int TYPE_SINGLE_INSTANCE_DEPRECATED = 4;
/*      */   public static final int TYPE_REPEATING = 5;
/*      */   public static final int TYPE_SINGLE_DATES = 6;
/*      */   static final String FN_RULE_TYPE = "t";
/*      */   static final int RULE_SIMPLE_REPEATING_RULE = 2;
/*      */   static final int RULE_EXCEPTION_RULE = 3;
/*      */   static final int RULE_RECURRENCE_RULE = 4;
/*      */   static final int RULE_SINGLE_INSTANCE_DEPRECATED = 5;
/*      */   static final int RULE_SINGLE_DATES = 6;
/*      */   
/*      */   public static abstract interface IRecurrence
/*      */     extends Cloneable
/*      */   {
/*      */     public abstract Metadata encodeMetadata();
/*      */     
/*      */     public abstract List<CalendarItem.Instance> expandInstances(int paramInt, long paramLong1, long paramLong2)
/*      */       throws ServiceException;
/*      */     
/*      */     public abstract ParsedDateTime getStartTime();
/*      */     
/*      */     public abstract ParsedDateTime getEndTime()
/*      */       throws ServiceException;
/*      */     
/*      */     public abstract Object clone();
/*      */     
/*      */     public abstract int getType();
/*      */     
/*      */     public abstract Iterator addRulesIterator();
/*      */     
/*      */     public abstract Iterator subRulesIterator();
/*      */     
/*      */     public abstract InviteInfo getInviteInfo();
/*      */     
/*      */     public abstract void setInviteId(InviteInfo paramInviteInfo);
/*      */     
/*      */     public abstract Element toXml(Element paramElement);
/*      */   }
/*      */   
/*      */   public static abstract interface IException
/*      */     extends Recurrence.IRecurrence
/*      */   {
/*      */     public abstract boolean matches(long paramLong);
/*      */     
/*      */     public abstract RecurId getRecurId();
/*      */   }
/*      */   
/*      */   public static IRecurrence decodeMetadata(Metadata meta, TimeZoneMap tzmap)
/*      */     throws ServiceException
/*      */   {
/*      */     try
/*      */     {
/*  210 */       int ruleType = (int)meta.getLong("t");
/*      */       
/*  212 */       switch (ruleType) {
/*      */       case 2: 
/*  214 */         return new SimpleRepeatingRule(meta, tzmap);
/*      */       case 3: 
/*  216 */         return new ExceptionRule(meta, tzmap);
/*      */       case 4: 
/*  218 */         return new RecurrenceRule(meta, tzmap);
/*      */       case 6: 
/*  220 */         SingleDates sdates = new SingleDates(meta, tzmap);
/*  221 */         return (sdates.getRdateExdate().isEXDATE()) || (DebugConfig.enableRdate) ? sdates : null;
/*      */       }
/*      */     } catch (ParseException e) {
/*  224 */       throw ServiceException.FAILURE("Parse excetion on metadata: " + meta, e);
/*      */     }
/*  226 */     throw new IllegalArgumentException("Unknown IRecur type: " + meta.get("t"));
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static abstract interface IInstanceGeneratingRule
/*      */     extends Recurrence.IRecurrence
/*      */   {
/*      */     public abstract InviteInfo getInviteInfo();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static class MultiRuleSorter
/*      */   {
/*      */     public Metadata encodeMetadata()
/*      */     {
/*  250 */       Metadata meta = new Metadata();
/*  251 */       meta.put("nr", this.mRules.size());
/*  252 */       for (int i = 0; i < this.mRules.size(); i++)
/*  253 */         meta.put("r" + i, ((Recurrence.IRecurrence)this.mRules.get(i)).encodeMetadata());
/*  254 */       return meta; }
/*      */     
/*      */     private static final String FN_NUM_RULES = "nr";
/*      */     private static final String FN_RULE = "r";
/*      */     private final List<Recurrence.IRecurrence> mRules;
/*  259 */     public Object clone() { List<Recurrence.IRecurrence> newRules = new ArrayList();
/*  260 */       for (Iterator iter = this.mRules.iterator(); iter.hasNext();) {
/*  261 */         Recurrence.IRecurrence rule = (Recurrence.IRecurrence)iter.next();
/*  262 */         newRules.add((Recurrence.IRecurrence)rule.clone());
/*      */       }
/*  264 */       return new MultiRuleSorter(newRules);
/*      */     }
/*      */     
/*      */     public Iterator<Recurrence.IRecurrence> iterator() {
/*  268 */       return this.mRules.iterator();
/*      */     }
/*      */     
/*      */     public MultiRuleSorter(Metadata meta, TimeZoneMap tzmap) throws ServiceException {
/*  272 */       int numRules = (int)meta.getLong("nr");
/*  273 */       this.mRules = new ArrayList(numRules);
/*  274 */       for (int i = 0; i < numRules; i++) {
/*      */         try {
/*  276 */           Recurrence.IRecurrence recurrence = Recurrence.decodeMetadata(meta.getMap("r" + i), tzmap);
/*  277 */           if (recurrence != null) {
/*  278 */             this.mRules.add(recurrence);
/*      */           }
/*      */         } catch (Exception e) {}
/*      */       }
/*      */     }
/*      */     
/*      */     public MultiRuleSorter(List<Recurrence.IRecurrence> rules) {
/*  285 */       assert ((rules == null) || (rules.size() == 0) || ((rules.get(0) instanceof Recurrence.IInstanceGeneratingRule)));
/*  286 */       this.mRules = rules;
/*      */     }
/*      */     
/*      */     public void setInviteId(InviteInfo invId) {
/*  290 */       for (Iterator iter = this.mRules.iterator(); iter.hasNext();) {
/*  291 */         Recurrence.IRecurrence cur = (Recurrence.IRecurrence)iter.next();
/*  292 */         cur.setInviteId(invId);
/*      */       }
/*      */     }
/*      */     
/*      */     public Element toXml(Element parent) {
/*  297 */       for (Iterator iter = this.mRules.iterator(); iter.hasNext();) {
/*  298 */         Recurrence.IRecurrence cur = (Recurrence.IRecurrence)iter.next();
/*  299 */         parent.addElement(cur.toXml(parent));
/*      */       }
/*  301 */       return parent;
/*      */     }
/*      */     
/*      */     List<CalendarItem.Instance> expandInstances(int calItemId, long start, long end) throws ServiceException
/*      */     {
/*  306 */       List[] lists = new ArrayList[this.mRules.size()];
/*  307 */       int num = 0;
/*  308 */       for (Iterator iter = this.mRules.iterator(); iter.hasNext();) {
/*  309 */         Recurrence.IRecurrence cur = (Recurrence.IRecurrence)iter.next();
/*  310 */         lists[num] = cur.expandInstances(calItemId, start, end);
/*  311 */         num++;
/*      */       }
/*      */       
/*  314 */       List<CalendarItem.Instance> toRet = new LinkedList();
/*  315 */       ListUtil.mergeSortedLists(toRet, lists, true);
/*      */       
/*  317 */       return toRet;
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/*  322 */       StringBuffer toRet = new StringBuffer();
/*  323 */       toRet.append("(");
/*  324 */       for (Iterator iter = this.mRules.iterator(); iter.hasNext();) {
/*  325 */         Recurrence.IRecurrence rule = (Recurrence.IRecurrence)iter.next();
/*  326 */         toRet.append(rule.toString());
/*      */       }
/*  328 */       toRet.append(")");
/*  329 */       return toRet.toString();
/*      */     }
/*      */     
/*      */     public ParsedDateTime getStartTime() {
/*  333 */       ParsedDateTime earliestStart = null;
/*  334 */       for (Iterator iter = this.mRules.iterator(); iter.hasNext();) {
/*  335 */         Recurrence.IRecurrence cur = (Recurrence.IRecurrence)iter.next();
/*  336 */         ParsedDateTime start = cur.getStartTime();
/*  337 */         if ((earliestStart == null) || ((start != null) && (start.compareTo(earliestStart) < 0))) {
/*  338 */           earliestStart = start;
/*      */         }
/*      */       }
/*  341 */       return earliestStart;
/*      */     }
/*      */     
/*      */     public ParsedDateTime getEndTime() throws ServiceException {
/*  345 */       ParsedDateTime latestEnd = null;
/*  346 */       for (Iterator iter = this.mRules.iterator(); iter.hasNext();) {
/*  347 */         Recurrence.IRecurrence cur = (Recurrence.IRecurrence)iter.next();
/*  348 */         ParsedDateTime end = cur.getEndTime();
/*  349 */         if ((latestEnd == null) || ((end != null) && (end.compareTo(latestEnd) > 0))) {
/*  350 */           latestEnd = end;
/*      */         }
/*      */       }
/*  353 */       return latestEnd;
/*      */     }
/*      */   }
/*      */   
/*      */   public static class SingleDates implements Recurrence.IInstanceGeneratingRule {
/*      */     private static final String FN_RDATE_EXDATE = "rexd";
/*      */     private static final String FN_DEFAULT_DURATION = "defdur";
/*      */     private static final String FN_INVID = "inv";
/*      */     private final RdateExdate mRdateExdate;
/*      */     private final ParsedDuration mDefaultDuration;
/*      */     private InviteInfo mInvId;
/*      */     private List<DateValue> mDates;
/*      */     
/*  366 */     public int getType() { return 6; }
/*      */     
/*  368 */     public RdateExdate getRdateExdate() { return this.mRdateExdate; }
/*      */     
/*      */ 
/*  371 */     public Iterator addRulesIterator() { return null; }
/*      */     
/*  373 */     public Iterator subRulesIterator() { return null; }
/*      */     
/*      */     public void setInviteId(InviteInfo invId)
/*      */     {
/*  377 */       this.mInvId = invId;
/*      */     }
/*      */     
/*      */     public InviteInfo getInviteInfo()
/*      */     {
/*  382 */       return this.mInvId;
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/*  387 */       StringBuilder toRet = new StringBuilder("[");
/*  388 */       if (this.mRdateExdate != null) {
/*  389 */         if (this.mRdateExdate.isRDATE()) {
/*  390 */           toRet.append("rdate=[");
/*      */         } else
/*  392 */           toRet.append("exdate=[");
/*  393 */         toRet.append(this.mRdateExdate.toString()).append("]");
/*      */       } else {
/*  395 */         toRet.append("rdate/exdate=<none>");
/*      */       }
/*  397 */       toRet.append(", defaultDuration=").append(this.mDefaultDuration.toString());
/*  398 */       if (this.mInvId != null)
/*  399 */         toRet.append(", InvId=").append(this.mInvId.toString());
/*  400 */       toRet.append("]");
/*      */       
/*  402 */       return toRet.toString();
/*      */     }
/*      */     
/*      */     public ParsedDateTime getStartTime()
/*      */     {
/*  407 */       ParsedDateTime start = null;
/*  408 */       for (DateValue val : this.mDates) {
/*  409 */         ParsedDateTime valStart = val.getStartTime();
/*  410 */         if ((start == null) || (start.compareTo(valStart) > 0))
/*  411 */           start = valStart;
/*      */       }
/*  413 */       return start;
/*      */     }
/*      */     
/*      */     public ParsedDateTime getEndTime()
/*      */     {
/*  418 */       ParsedDateTime end = null;
/*  419 */       for (DateValue val : this.mDates) {
/*  420 */         ParsedDateTime valEnd = val.getEndTime();
/*  421 */         if ((end == null) || (end.compareTo(valEnd) < 0))
/*  422 */           end = valEnd;
/*      */       }
/*  424 */       return end;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */     public List<CalendarItem.Instance> expandInstances(int calItemId, long start, long end)
/*      */     {
/*  432 */       return expandInstances(calItemId);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */     public List<CalendarItem.Instance> expandInstances(int calItemId)
/*      */     {
/*  439 */       List<CalendarItem.Instance> list = new ArrayList();
/*  440 */       if ((this.mRdateExdate.isEXDATE()) || (DebugConfig.enableRdate)) {
/*  441 */         for (DateValue val : this.mDates) {
/*  442 */           ParsedDateTime valStart = val.getStartTime();
/*  443 */           ParsedDateTime valEnd = val.getEndTime();
/*  444 */           boolean allDay = (!valStart.hasTime()) || ((valStart.hasZeroTime()) && (this.mDefaultDuration != null) && (this.mDefaultDuration.isMultipleOfDays()));
/*      */           
/*  446 */           list.add(new CalendarItem.Instance(calItemId, this.mInvId, true, true, valStart.getUtcTime(), valEnd.getUtcTime(), allDay, valStart.getOffset(), valEnd.getOffset(), true, true));
/*      */         }
/*      */         
/*      */ 
/*      */ 
/*  451 */         Collections.sort(list);
/*      */       }
/*  453 */       return list;
/*      */     }
/*      */     
/*      */     public Metadata encodeMetadata()
/*      */     {
/*  458 */       Metadata meta = new Metadata();
/*  459 */       meta.put("t", 6L);
/*  460 */       meta.put("rexd", this.mRdateExdate.encodeMetadata());
/*  461 */       meta.put("defdur", this.mDefaultDuration);
/*  462 */       if (this.mInvId != null)
/*  463 */         meta.put("inv", this.mInvId.encodeMetadata());
/*  464 */       return meta;
/*      */     }
/*      */     
/*      */     SingleDates(Metadata meta, TimeZoneMap tzmap) throws ServiceException, ParseException
/*      */     {
/*  469 */       Metadata rexdate = meta.getMap("rexd");
/*  470 */       this.mRdateExdate = RdateExdate.decodeMetadata(rexdate, tzmap);
/*  471 */       this.mDefaultDuration = ParsedDuration.parse(meta.get("defdur"));
/*  472 */       Metadata metaInvId = meta.getMap("inv", true);
/*  473 */       if (metaInvId != null)
/*  474 */         this.mInvId = InviteInfo.fromMetadata(metaInvId, tzmap);
/*  475 */       setDates();
/*      */     }
/*      */     
/*      */     public SingleDates(RdateExdate rexdate, ParsedDuration defaultDuration) {
/*  479 */       this(rexdate, defaultDuration, null);
/*      */     }
/*      */     
/*      */     SingleDates(RdateExdate rexdate, ParsedDuration defaultDuration, InviteInfo invId) {
/*  483 */       this.mRdateExdate = rexdate;
/*  484 */       this.mDefaultDuration = defaultDuration;
/*  485 */       this.mInvId = invId;
/*  486 */       setDates();
/*      */     }
/*      */     
/*      */     private void setDates() {
/*  490 */       List<DateValue> list = new ArrayList(this.mRdateExdate.numValues());
/*      */       
/*  492 */       for (Iterator<Object> iter = this.mRdateExdate.valueIterator(); iter.hasNext();) {
/*  493 */         Object val = iter.next();
/*  494 */         if ((val instanceof ParsedDateTime)) {
/*  495 */           ParsedDateTime start = (ParsedDateTime)val;
/*  496 */           ParsedDateTime end = start.add(this.mDefaultDuration);
/*  497 */           DateValue dtval = new DateValue(start, end);
/*  498 */           list.add(dtval);
/*  499 */         } else if ((val instanceof Period)) {
/*  500 */           Period p = (Period)val;
/*  501 */           DateValue dtval = new DateValue(p.getStart(), p.getEnd());
/*  502 */           list.add(dtval);
/*      */         }
/*      */       }
/*  505 */       this.mDates = list;
/*      */     }
/*      */     
/*      */     public Element toXml(Element parent)
/*      */     {
/*  510 */       return this.mRdateExdate.toXml(parent);
/*      */     }
/*      */     
/*      */     public Object clone()
/*      */     {
/*  515 */       return new SingleDates(this.mRdateExdate == null ? null : (RdateExdate)this.mRdateExdate.clone(), this.mDefaultDuration == null ? null : (ParsedDuration)this.mDefaultDuration.clone(), this.mInvId == null ? null : (InviteInfo)this.mInvId.clone());
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */     private static class DateValue
/*      */     {
/*      */       private final ParsedDateTime mStart;
/*      */       
/*      */ 
/*      */       private final ParsedDateTime mEnd;
/*      */       
/*      */ 
/*      */ 
/*      */       public DateValue(ParsedDateTime start, ParsedDateTime end)
/*      */       {
/*  531 */         assert ((start != null) && (end != null));
/*  532 */         this.mStart = start;
/*  533 */         this.mEnd = end;
/*      */       }
/*      */       
/*  536 */       public ParsedDateTime getStartTime() { return this.mStart; }
/*  537 */       public ParsedDateTime getEndTime() { return this.mEnd; }
/*      */       
/*      */       public String toString()
/*      */       {
/*  541 */         StringBuilder sb = new StringBuilder();
/*  542 */         sb.append("[start=").append(this.mStart.toString());
/*  543 */         sb.append(", end=").append(this.mEnd.toString());
/*  544 */         sb.append("]");
/*  545 */         return sb.toString();
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static class SimpleRepeatingRule
/*      */     implements Recurrence.IInstanceGeneratingRule
/*      */   {
/*  557 */     Map<String, List<CalendarItem.Instance>> expandMap = new HashMap();
/*      */     private static final String FN_DTSTART = "dts";
/*      */     private static final String FN_DURATION = "dur";
/*      */     
/*  561 */     public SimpleRepeatingRule(ParsedDateTime dtstart, ParsedDuration duration, ZRecur recur, InviteInfo invId) { this.mDtStart = dtstart;
/*  562 */       this.mRecur = recur;
/*  563 */       fixupRecurUntil();
/*  564 */       this.mInvId = invId;
/*  565 */       this.mDuration = duration;
/*  566 */       if (this.mDuration == null) {
/*  567 */         if ((this.mDtStart != null) && (!this.mDtStart.hasTime())) {
/*  568 */           this.mDuration = ParsedDuration.ONE_DAY;
/*      */         } else
/*  570 */           this.mDuration = ParsedDuration.ONE_SECOND;
/*      */       }
/*      */     }
/*      */     
/*      */     private void fixupRecurUntil() {
/*  575 */       if ((this.mRecur != null) && (this.mDtStart != null)) {
/*  576 */         ParsedDateTime until = this.mRecur.getUntil();
/*  577 */         if ((until != null) && (until.hasTime() != this.mDtStart.hasTime()))
/*      */         {
/*  579 */           if (this.mDtStart.hasTime())
/*      */           {
/*  581 */             Date dayEnd = until.getDateForRecurUntil(this.mDtStart.getTimeZone());
/*  582 */             ParsedDateTime untilUtc = ParsedDateTime.fromUTCTime(dayEnd.getTime());
/*  583 */             this.mRecur.setUntil(untilUtc);
/*      */           } else {
/*  585 */             until.setHasTime(false);
/*      */           } }
/*      */       }
/*      */     }
/*      */     
/*      */     private static final String FN_RECUR = "recur";
/*      */     private static final String FN_INVID = "inv";
/*  592 */     public int getType() { return 5; }
/*      */     
/*  594 */     public Iterator addRulesIterator() { return null; }
/*      */     
/*  596 */     public Iterator subRulesIterator() { return null; }
/*      */     
/*      */     public void setInviteId(InviteInfo invId)
/*      */     {
/*  600 */       this.mInvId = invId;
/*      */     }
/*      */     
/*      */     public InviteInfo getInviteInfo()
/*      */     {
/*  605 */       return this.mInvId;
/*      */     }
/*      */     
/*      */     public Element toXml(Element parent)
/*      */     {
/*  610 */       Element rule = parent.addElement("rule");
/*      */       
/*      */ 
/*  613 */       String freq = IcalXmlStrMap.sFreqMap.toXml(this.mRecur.getFrequency().toString());
/*  614 */       rule.addAttribute("freq", freq);
/*      */       
/*      */ 
/*  617 */       ParsedDateTime untilDate = this.mRecur.getUntil();
/*  618 */       if (untilDate != null) {
/*  619 */         Element untilElt = rule.addElement("until");
/*  620 */         untilElt.addAttribute("d", untilDate.getDateTimePartString(false));
/*      */       }
/*      */       else {
/*  623 */         int count = this.mRecur.getCount();
/*  624 */         if (count > 0) {
/*  625 */           rule.addElement("count").addAttribute("num", count);
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*  630 */       int ival = this.mRecur.getInterval();
/*  631 */       if (ival > 0) {
/*  632 */         rule.addElement("interval").addAttribute("ival", ival);
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  637 */       List<Integer> bySecond = this.mRecur.getBySecondList();
/*  638 */       if (!bySecond.isEmpty()) {
/*  639 */         rule.addElement("bysecond").addAttribute("seclist", ZRecur.listAsStr(bySecond));
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  644 */       List<Integer> byMinute = this.mRecur.getByMinuteList();
/*  645 */       if (!byMinute.isEmpty()) {
/*  646 */         rule.addElement("byminute").addAttribute("minlist", ZRecur.listAsStr(byMinute));
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  651 */       List<Integer> byHour = this.mRecur.getByHourList();
/*  652 */       if (!byHour.isEmpty()) {
/*  653 */         rule.addElement("byhour").addAttribute("hrlist", ZRecur.listAsStr(byHour));
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  658 */       List<ZRecur.ZWeekDayNum> byDay = this.mRecur.getByDayList();
/*  659 */       Element bydayElt; if (!byDay.isEmpty()) {
/*  660 */         bydayElt = rule.addElement("byday");
/*  661 */         for (ZRecur.ZWeekDayNum wdn : byDay) {
/*  662 */           Element wkdayElt = bydayElt.addElement("wkday");
/*  663 */           if (wdn.mOrdinal != 0)
/*  664 */             wkdayElt.addAttribute("ordwk", wdn.mOrdinal);
/*  665 */           wkdayElt.addAttribute("day", wdn.mDay.toString());
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*  670 */       List<Integer> byMonthDay = this.mRecur.getByMonthDayList();
/*  671 */       if (!byMonthDay.isEmpty()) {
/*  672 */         rule.addElement("bymonthday").addAttribute("modaylist", ZRecur.listAsStr(byMonthDay));
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  677 */       List<Integer> byYearDay = this.mRecur.getByYearDayList();
/*  678 */       if (!byYearDay.isEmpty()) {
/*  679 */         rule.addElement("byyearday").addAttribute("yrdaylist", ZRecur.listAsStr(byYearDay));
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  684 */       List<Integer> byWeekNo = this.mRecur.getByWeekNoList();
/*  685 */       if (!byWeekNo.isEmpty()) {
/*  686 */         rule.addElement("byweekno").addAttribute("wklist", ZRecur.listAsStr(byWeekNo));
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  691 */       List<Integer> byMonth = this.mRecur.getByMonthList();
/*  692 */       if (!byMonth.isEmpty()) {
/*  693 */         rule.addElement("bymonth").addAttribute("molist", ZRecur.listAsStr(byMonth));
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  698 */       List<Integer> bySetPos = this.mRecur.getBySetPosList();
/*  699 */       if (!bySetPos.isEmpty()) {
/*  700 */         rule.addElement("bysetpos").addAttribute("poslist", ZRecur.listAsStr(bySetPos));
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  705 */       ZWeekDay wkst = this.mRecur.getWkSt();
/*  706 */       if (wkst != null) {
/*  707 */         rule.addElement("wkst").addAttribute("day", wkst.toString());
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  721 */       return rule;
/*      */     }
/*      */     
/*      */ 
/*      */     public List<CalendarItem.Instance> expandInstances(int calItemId, long start, long end)
/*      */     {
/*  727 */       if (this.mDtStart == null) {
/*  728 */         ZimbraLog.calendar.warn("Unable to expand a recurrence with no DTSTART");
/*  729 */         return new ArrayList();
/*      */       }
/*  731 */       String KEY = String.valueOf(calItemId) + '-' + start + '-' + end;
/*  732 */       List<CalendarItem.Instance> toRet = (List)this.expandMap.get(KEY);
/*  733 */       if (toRet != null) {
/*  734 */         return toRet;
/*      */       }
/*  736 */       ICalTimeZone tz = this.mDtStart.getTimeZone();
/*  737 */       if (tz == null)
/*  738 */         tz = ICalTimeZone.getUTC();
/*      */       try {
/*  740 */         long duration = 0L;
/*  741 */         if (this.mDuration != null) {
/*  742 */           ParsedDateTime et = this.mDtStart.add(this.mDuration);
/*  743 */           duration = et.getUtcTime() - this.mDtStart.getUtcTime();
/*      */         }
/*  745 */         List<Date> dateList = this.mRecur.expandRecurrenceOverRange(this.mDtStart, start - duration, end);
/*      */         
/*  747 */         toRet = new ArrayList(dateList.size());
/*      */         
/*  749 */         num = 0;
/*  750 */         for (iter = dateList.iterator(); iter.hasNext();) {
/*  751 */           Date cur = (Date)iter.next();
/*  752 */           long instStart = cur.getTime();
/*      */           long instEnd;
/*  754 */           long instEnd; if (this.mDuration != null) {
/*  755 */             ParsedDateTime startDt = ParsedDateTime.fromUTCTime(instStart, tz);
/*  756 */             instEnd = startDt.add(this.mDuration).getUtcTime();
/*      */           } else {
/*  758 */             instEnd = instStart;
/*      */           }
/*  760 */           if ((instStart < end) && (instEnd > start)) {
/*  761 */             int startTzo = tz.getOffset(instStart);
/*  762 */             int endTzo = tz.getOffset(instEnd);
/*  763 */             boolean allDay = (!this.mDtStart.hasTime()) || ((this.mDtStart.hasZeroTime()) && (this.mDuration != null) && (this.mDuration.isMultipleOfDays()));
/*  764 */             toRet.add(num++, new CalendarItem.Instance(calItemId, this.mInvId, true, true, instStart, instEnd, allDay, startTzo, endTzo, false, false));
/*      */           }
/*      */         }
/*      */       } catch (ServiceException se) {
/*      */         int num;
/*      */         Iterator iter;
/*  770 */         ZimbraLog.calendar.warn("ServiceException expanding recurrence rule: " + this.mRecur.toString(), se);
/*  771 */         toRet = new ArrayList();
/*      */       }
/*      */       catch (IllegalArgumentException iae) {
/*  774 */         ZimbraLog.calendar.warn("Invalid recurrence rule: " + this.mRecur.toString(), iae);
/*  775 */         toRet = new ArrayList();
/*      */       }
/*      */       
/*  778 */       this.expandMap.put(KEY, toRet);
/*  779 */       return toRet;
/*      */     }
/*      */     
/*  782 */     public ZRecur getRule() { return this.mRecur; }
/*      */     
/*      */ 
/*      */     public ParsedDateTime getStartTime()
/*      */     {
/*  787 */       return this.mDtStart;
/*      */     }
/*      */     
/*      */     public ParsedDateTime getEndTime() throws ServiceException {
/*  791 */       if (this.mDtStart == null)
/*      */       {
/*  793 */         return ParsedDateTime.MAX_DATETIME; }
/*  794 */       if (this.mRecur != null) {
/*  795 */         long endMillis = this.mRecur.getEstimatedEndTime(this.mDtStart).getTime();
/*  796 */         if (this.mRecur.getCount() > 0)
/*      */         {
/*  798 */           List<Date> dates = this.mRecur.expandRecurrenceOverRange(this.mDtStart, this.mDtStart.getUtcTime(), endMillis);
/*  799 */           if (!dates.isEmpty())
/*  800 */             endMillis = ((Date)dates.get(dates.size() - 1)).getTime();
/*      */         }
/*  802 */         ParsedDateTime end = ParsedDateTime.fromUTCTime(endMillis, this.mDtStart.getTimeZone());
/*  803 */         if (this.mDuration != null)
/*  804 */           end = end.add(this.mDuration);
/*  805 */         return end;
/*      */       }
/*      */       
/*  808 */       ParsedDuration dur = this.mDuration != null ? this.mDuration : ParsedDuration.parse(false, 0, 0, 0, 0, 1);
/*  809 */       return this.mDtStart.add(dur);
/*      */     }
/*      */     
/*      */ 
/*      */     public String toString()
/*      */     {
/*  815 */       StringBuilder toRet = new StringBuilder();
/*  816 */       toRet.append("RULE(FIRST=").append(this.mDtStart != null ? this.mDtStart.getDate() : "<none>");
/*  817 */       toRet.append(",DUR=").append(this.mDuration);
/*  818 */       toRet.append(",RECUR=").append(this.mRecur.toString());
/*  819 */       return toRet.toString();
/*      */     }
/*      */     
/*      */ 
/*      */     private ParsedDateTime mDtStart;
/*      */     private final ZRecur mRecur;
/*      */     private ParsedDuration mDuration;
/*      */     private InviteInfo mInvId;
/*      */     public Metadata encodeMetadata()
/*      */     {
/*  829 */       Metadata meta = new Metadata();
/*  830 */       meta.put("t", 2L);
/*  831 */       meta.put("dts", this.mDtStart);
/*  832 */       meta.put("dur", this.mDuration);
/*  833 */       meta.put("recur", this.mRecur);
/*  834 */       if (this.mInvId != null) {
/*  835 */         meta.put("inv", this.mInvId.encodeMetadata());
/*      */       }
/*  837 */       return meta;
/*      */     }
/*      */     
/*      */     public Object clone()
/*      */     {
/*  842 */       return new SimpleRepeatingRule(this.mDtStart == null ? null : (ParsedDateTime)this.mDtStart.clone(), this.mDuration == null ? null : (ParsedDuration)this.mDuration.clone(), this.mRecur == null ? null : (ZRecur)this.mRecur.clone(), this.mInvId == null ? null : (InviteInfo)this.mInvId.clone());
/*      */     }
/*      */     
/*      */     public SimpleRepeatingRule(Metadata meta, TimeZoneMap tzmap)
/*      */       throws ServiceException
/*      */     {
/*      */       try
/*      */       {
/*  850 */         this.mDtStart = ParsedDateTime.parse(meta.get("dts", null), tzmap);
/*  851 */         this.mDuration = ParsedDuration.parse(meta.get("dur", null));
/*  852 */         if (this.mDuration == null) {
/*  853 */           if ((this.mDtStart != null) && (!this.mDtStart.hasTime())) {
/*  854 */             this.mDuration = ParsedDuration.ONE_DAY;
/*      */           } else
/*  856 */             this.mDuration = ParsedDuration.ONE_SECOND;
/*      */         }
/*      */       } catch (ParseException e) {
/*  859 */         throw ServiceException.FAILURE("ParseException ", e);
/*      */       }
/*  861 */       this.mRecur = new ZRecur(meta.get("recur").toString(), tzmap);
/*  862 */       Metadata metaInvId = meta.getMap("inv", true);
/*  863 */       if (metaInvId != null) {
/*  864 */         this.mInvId = InviteInfo.fromMetadata(metaInvId, tzmap);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   public static abstract class CompoundRuleBase
/*      */     implements Recurrence.IRecurrence
/*      */   {
/*      */     static final String FN_DTSTART = "dts";
/*      */     
/*      */     static final String FN_DURATION = "duration";
/*      */     
/*      */     static final String FN_ADDRULES = "add";
/*      */     
/*      */     static final String FN_SUBRULES = "sub";
/*      */     
/*      */     static final String FN_INVID = "invid";
/*      */     protected ParsedDateTime mDtStart;
/*      */     protected ParsedDuration mDuration;
/*      */     protected Recurrence.MultiRuleSorter mAddRules;
/*      */     protected Recurrence.MultiRuleSorter mSubtractRules;
/*      */     protected InviteInfo mInvId;
/*      */     
/*      */     protected CompoundRuleBase(ParsedDateTime dtstart, ParsedDuration duration, InviteInfo invId, List<Recurrence.IRecurrence> addRules, List<Recurrence.IRecurrence> subtractRules)
/*      */     {
/*  890 */       this.mDtStart = dtstart;
/*  891 */       this.mDuration = duration;
/*  892 */       if (this.mDuration == null) {
/*  893 */         if ((this.mDtStart != null) && (!this.mDtStart.hasTime())) {
/*  894 */           this.mDuration = ParsedDuration.ONE_DAY;
/*      */         } else
/*  896 */           this.mDuration = ParsedDuration.ONE_SECOND;
/*      */       }
/*  898 */       this.mInvId = invId;
/*  899 */       this.mAddRules = new Recurrence.MultiRuleSorter(addRules);
/*  900 */       if (subtractRules.size() > 0) {
/*  901 */         this.mSubtractRules = new Recurrence.MultiRuleSorter(subtractRules);
/*      */       } else {
/*  903 */         this.mSubtractRules = null;
/*      */       }
/*      */     }
/*      */     
/*      */     public void setInviteId(InviteInfo invId)
/*      */     {
/*  909 */       this.mInvId = invId;
/*      */       
/*  911 */       this.mAddRules.setInviteId(invId);
/*  912 */       if (this.mSubtractRules != null) {
/*  913 */         this.mSubtractRules.setInviteId(invId);
/*      */       }
/*      */     }
/*      */     
/*      */     public InviteInfo getInviteInfo()
/*      */     {
/*  919 */       return this.mInvId;
/*      */     }
/*      */     
/*      */ 
/*      */     protected CompoundRuleBase(ParsedDateTime dtstart, ParsedDuration duration, InviteInfo invId)
/*      */     {
/*  925 */       this.mDtStart = dtstart;
/*  926 */       this.mDuration = duration;
/*  927 */       if (this.mDuration == null) {
/*  928 */         if ((this.mDtStart != null) && (!this.mDtStart.hasTime())) {
/*  929 */           this.mDuration = ParsedDuration.ONE_DAY;
/*      */         } else
/*  931 */           this.mDuration = ParsedDuration.ONE_SECOND;
/*      */       }
/*  933 */       this.mInvId = invId;
/*  934 */       this.mAddRules = null;
/*  935 */       this.mSubtractRules = null;
/*      */     }
/*      */     
/*      */ 
/*  939 */     public Iterator<Recurrence.IRecurrence> addRulesIterator() { return this.mAddRules.iterator(); }
/*      */     
/*      */     public Iterator<Recurrence.IRecurrence> subRulesIterator() {
/*  942 */       if (this.mSubtractRules != null) {
/*  943 */         return this.mSubtractRules.iterator();
/*      */       }
/*  945 */       return null;
/*      */     }
/*      */     
/*      */ 
/*      */     public List<CalendarItem.Instance> expandInstances(int calItemId, long start, long end)
/*      */       throws ServiceException
/*      */     {
/*  952 */       if (this.mDtStart == null) {
/*  953 */         ZimbraLog.calendar.warn("Unable to expand a recurrence with no DTSTART");
/*  954 */         return new ArrayList(0);
/*      */       }
/*      */       
/*      */       List<CalendarItem.Instance> toAdd;
/*      */       
/*      */       List<CalendarItem.Instance> toAdd;
/*      */       
/*  961 */       if (this.mAddRules != null) {
/*  962 */         toAdd = this.mAddRules.expandInstances(calItemId, start, end);
/*      */       } else {
/*  964 */         toAdd = new ArrayList(1);
/*      */       }
/*      */       
/*  967 */       long firstStart = this.mDtStart.getUtcTime();
/*  968 */       ParsedDateTime dtFirstEnd = this.mDuration != null ? this.mDtStart.add(this.mDuration) : null;
/*  969 */       long firstEnd = dtFirstEnd != null ? dtFirstEnd.getUtcTime() : firstStart;
/*  970 */       if ((firstStart < end) && (firstEnd > start)) {
/*  971 */         CalendarItem.Instance first = null;
/*  972 */         if (toAdd.size() > 0) {
/*  973 */           first = (CalendarItem.Instance)toAdd.get(0);
/*      */         }
/*      */         
/*  976 */         boolean allDay = (!this.mDtStart.hasTime()) || ((this.mDtStart.hasZeroTime()) && (this.mDuration != null) && (this.mDuration.isMultipleOfDays()));
/*  977 */         CalendarItem.Instance dtstartInst = new CalendarItem.Instance(calItemId, this.mInvId, true, true, firstStart, firstEnd, allDay, this.mDtStart.getOffset(), dtFirstEnd != null ? dtFirstEnd.getOffset() : 0, false, true);
/*      */         
/*      */ 
/*      */ 
/*  981 */         if ((first == null) || (first.compareTo(dtstartInst) != 0)) {
/*  982 */           toAdd.add(0, dtstartInst);
/*      */         }
/*      */       }
/*      */       
/*  986 */       if (this.mSubtractRules == null)
/*  987 */         return toAdd;
/*  988 */       List<CalendarItem.Instance> toExclude = this.mSubtractRules.expandInstances(calItemId, start, end);
/*  989 */       return ListUtil.subtractSortedLists(toAdd, toExclude, new CalendarItem.Instance.StartTimeComparator());
/*      */     }
/*      */     
/*      */ 
/*      */     public Element toXml(Element parent)
/*      */     {
/*  995 */       if (this.mAddRules != null) {
/*  996 */         Element addElt = parent.addElement("add");
/*  997 */         this.mAddRules.toXml(addElt);
/*      */       }
/*  999 */       if (this.mSubtractRules != null) {
/* 1000 */         Element excludeElt = parent.addElement("exclude");
/* 1001 */         this.mSubtractRules.toXml(excludeElt);
/*      */       }
/* 1003 */       return parent;
/*      */     }
/*      */     
/*      */ 
/*      */     public ParsedDateTime getStartTime()
/*      */     {
/* 1009 */       return this.mDtStart;
/*      */     }
/*      */     
/*      */     public ParsedDateTime getEndTime() throws ServiceException
/*      */     {
/* 1014 */       if (this.mAddRules != null)
/* 1015 */         return this.mAddRules.getEndTime();
/* 1016 */       if (this.mDtStart != null) {
/* 1017 */         return this.mDtStart.add(this.mDuration);
/*      */       }
/* 1019 */       return null;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public Metadata encodeMetadata()
/*      */     {
/* 1031 */       Metadata meta = new Metadata();
/* 1032 */       meta.put("dts", this.mDtStart);
/* 1033 */       meta.put("duration", this.mDuration);
/* 1034 */       if (this.mAddRules != null)
/* 1035 */         meta.put("add", this.mAddRules.encodeMetadata());
/* 1036 */       if (this.mSubtractRules != null)
/* 1037 */         meta.put("sub", this.mSubtractRules.encodeMetadata());
/* 1038 */       if (this.mInvId != null) {
/* 1039 */         meta.put("invid", this.mInvId.encodeMetadata());
/*      */       }
/* 1041 */       return meta;
/*      */     }
/*      */     
/*      */     protected CompoundRuleBase(Metadata meta, TimeZoneMap tzmap) throws ServiceException, ParseException
/*      */     {
/* 1046 */       String str = meta.get("dts", null);
/* 1047 */       this.mDtStart = ParsedDateTime.parse(str, tzmap);
/* 1048 */       this.mDuration = ParsedDuration.parse(meta.get("duration", null));
/* 1049 */       if (this.mDuration == null) {
/* 1050 */         if ((this.mDtStart != null) && (!this.mDtStart.hasTime())) {
/* 1051 */           this.mDuration = ParsedDuration.ONE_DAY;
/*      */         } else {
/* 1053 */           this.mDuration = ParsedDuration.ONE_SECOND;
/*      */         }
/*      */       }
/* 1056 */       Metadata metaRules = meta.getMap("add", true);
/* 1057 */       if (metaRules != null) {
/* 1058 */         this.mAddRules = new Recurrence.MultiRuleSorter(metaRules, tzmap);
/*      */       }
/* 1060 */       Metadata metaSubrules = meta.getMap("sub", true);
/* 1061 */       if (metaSubrules != null) {
/* 1062 */         this.mSubtractRules = new Recurrence.MultiRuleSorter(metaSubrules, tzmap);
/*      */       }
/*      */       
/* 1065 */       Metadata metaInvId = meta.getMap("invid", true);
/* 1066 */       if (metaInvId != null) {
/* 1067 */         this.mInvId = InviteInfo.fromMetadata(metaInvId, tzmap);
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*      */     protected CompoundRuleBase(ParsedDateTime dtstart, ParsedDuration duration, Recurrence.MultiRuleSorter addRules, Recurrence.MultiRuleSorter subtractRules, InviteInfo invID)
/*      */     {
/* 1074 */       this.mDtStart = dtstart;
/* 1075 */       this.mDuration = duration;
/* 1076 */       if (this.mDuration == null) {
/* 1077 */         if ((this.mDtStart != null) && (!this.mDtStart.hasTime())) {
/* 1078 */           this.mDuration = ParsedDuration.ONE_DAY;
/*      */         } else
/* 1080 */           this.mDuration = ParsedDuration.ONE_SECOND;
/*      */       }
/* 1082 */       this.mAddRules = addRules;
/* 1083 */       this.mSubtractRules = subtractRules;
/* 1084 */       this.mInvId = invID;
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/* 1089 */       StringBuffer toRet = new StringBuffer();
/* 1090 */       toRet.append("FIRST=").append(this.mDtStart != null ? this.mDtStart.getDate() : "<none>");
/* 1091 */       toRet.append(",DUR=").append(this.mDuration);
/* 1092 */       if (this.mAddRules != null) {
/* 1093 */         toRet.append("\n\t\tADD[").append(this.mAddRules.toString()).append("]");
/*      */       }
/* 1095 */       if (this.mSubtractRules != null) {
/* 1096 */         toRet.append("\n\t\tSUBTRACT[").append(this.mSubtractRules.toString()).append("]");
/*      */       }
/* 1098 */       return toRet.toString();
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public abstract Object clone();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static class CancellationRule
/*      */     implements Recurrence.IException
/*      */   {
/*      */     private static final String FN_RECURRENCE_ID = "recurId";
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     private final RecurId mRecurRange;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public CancellationRule(RecurId recurId)
/*      */     {
/* 1193 */       this.mRecurRange = recurId;
/*      */     }
/*      */     
/*      */ 
/* 1197 */     public int getType() { return 3; }
/*      */     
/* 1199 */     public Iterator addRulesIterator() { return null; }
/*      */     
/* 1201 */     public Iterator subRulesIterator() { return null; }
/*      */     
/*      */     public void setInviteId(InviteInfo invId) {}
/*      */     
/*      */     public InviteInfo getInviteInfo() {
/* 1206 */       return null;
/*      */     }
/*      */     
/*      */     CancellationRule(Metadata meta, TimeZoneMap tzmap) throws ServiceException, ParseException
/*      */     {
/* 1211 */       this.mRecurRange = RecurId.decodeMetadata(meta.getMap("recurId"), tzmap);
/*      */     }
/*      */     
/*      */     public Metadata encodeMetadata()
/*      */     {
/* 1216 */       Metadata meta = new Metadata();
/*      */       
/* 1218 */       meta.put("recurId", this.mRecurRange.encodeMetadata());
/* 1219 */       return meta;
/*      */     }
/*      */     
/*      */     public List<CalendarItem.Instance> expandInstances(int calItemId, long start, long end)
/*      */     {
/* 1224 */       return new ArrayList();
/*      */     }
/*      */     
/*      */     public ParsedDateTime getStartTime()
/*      */     {
/* 1229 */       return null;
/*      */     }
/*      */     
/*      */     public ParsedDateTime getEndTime()
/*      */     {
/* 1234 */       return null;
/*      */     }
/*      */     
/*      */     public Object clone()
/*      */     {
/* 1239 */       return new CancellationRule(this.mRecurRange == null ? null : (RecurId)this.mRecurRange.clone());
/*      */     }
/*      */     
/*      */     public Element toXml(Element parent)
/*      */     {
/* 1244 */       Element elt = parent.addElement("cancel");
/* 1245 */       this.mRecurRange.toXml(elt);
/*      */       
/* 1247 */       return elt;
/*      */     }
/*      */     
/*      */     public boolean matches(long date)
/*      */     {
/* 1252 */       return this.mRecurRange.withinRange(date);
/*      */     }
/*      */     
/*      */     public RecurId getRecurId()
/*      */     {
/* 1257 */       return this.mRecurRange;
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/* 1262 */       return String.format("CANCELLATION(%s)", new Object[] { this.mRecurRange == null ? "<null>" : this.mRecurRange.toString() });
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   public static class ExceptionRule
/*      */     extends Recurrence.CompoundRuleBase
/*      */     implements Recurrence.IException
/*      */   {
/*      */     static final String FN_RECURRENCE_ID = "recurId";
/*      */     
/*      */     static final String FN_RANGE_TYPE = "rgtyp";
/*      */     
/*      */     private final RecurId mRecurRange;
/*      */     
/*      */ 
/*      */     public ExceptionRule(RecurId recurrenceId, ParsedDateTime dtstart, ParsedDuration duration, InviteInfo invId, List<Recurrence.IRecurrence> addRules, List<Recurrence.IRecurrence> subtractRules)
/*      */     {
/* 1280 */       super(duration, invId, addRules, subtractRules);
/* 1281 */       this.mRecurRange = recurrenceId;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */     public ExceptionRule(RecurId recurrenceId, ParsedDateTime dtstart, ParsedDuration duration, InviteInfo invId)
/*      */     {
/* 1288 */       super(duration, invId);
/* 1289 */       this.mRecurRange = recurrenceId;
/*      */     }
/*      */     
/*      */     protected ExceptionRule(Metadata meta, TimeZoneMap tzmap) throws ParseException, ServiceException
/*      */     {
/* 1294 */       super(tzmap);
/* 1295 */       this.mRecurRange = RecurId.decodeMetadata(meta.getMap("recurId"), tzmap);
/*      */     }
/*      */     
/*      */     public int getType() {
/* 1299 */       return 2;
/*      */     }
/*      */     
/*      */     public List<CalendarItem.Instance> expandInstances(int calItemId, long start, long end) throws ServiceException
/*      */     {
/* 1304 */       List<CalendarItem.Instance> toRet = super.expandInstances(calItemId, start, end);
/*      */       
/* 1306 */       for (Iterator iter = toRet.iterator(); iter.hasNext();) {
/* 1307 */         CalendarItem.Instance cur = (CalendarItem.Instance)iter.next();
/* 1308 */         cur.setIsException(true);
/*      */       }
/* 1310 */       return toRet;
/*      */     }
/*      */     
/*      */ 
/*      */     public Element toXml(Element parent)
/*      */     {
/* 1316 */       Element elt = parent.addElement("except");
/* 1317 */       this.mRecurRange.toXml(elt);
/*      */       
/*      */ 
/* 1320 */       super.toXml(elt);
/*      */       
/* 1322 */       return elt;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */     public Metadata encodeMetadata()
/*      */     {
/* 1330 */       Metadata meta = super.encodeMetadata();
/* 1331 */       meta.put("t", 3L);
/* 1332 */       meta.put("recurId", this.mRecurRange.encodeMetadata());
/* 1333 */       return meta;
/*      */     }
/*      */     
/*      */     public boolean matches(long date)
/*      */     {
/* 1338 */       return this.mRecurRange.withinRange(date);
/*      */     }
/*      */     
/*      */     public RecurId getRecurId()
/*      */     {
/* 1343 */       return this.mRecurRange;
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/* 1348 */       StringBuffer toRet = new StringBuffer("EXCEPTION(");
/* 1349 */       toRet.append(this.mRecurRange.toString());
/* 1350 */       toRet.append(" ");
/* 1351 */       toRet.append(super.toString());
/* 1352 */       return toRet.toString();
/*      */     }
/*      */     
/*      */     private ExceptionRule(ExceptionRule other) {
/* 1356 */       super(other.mDuration == null ? null : (ParsedDuration)other.mDuration.clone(), other.mAddRules == null ? null : (Recurrence.MultiRuleSorter)other.mAddRules.clone(), other.mSubtractRules == null ? null : (Recurrence.MultiRuleSorter)other.mSubtractRules.clone(), other.mInvId == null ? null : (InviteInfo)other.mInvId.clone());
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 1361 */       this.mRecurRange = (other.mRecurRange == null ? null : (RecurId)other.mRecurRange.clone());
/*      */     }
/*      */     
/*      */     public Object clone()
/*      */     {
/* 1366 */       return new ExceptionRule(this);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public static class RecurrenceRule
/*      */     extends Recurrence.CompoundRuleBase
/*      */   {
/*      */     static final String FN_NUM_EXCEPTIONS = "numEx";
/*      */     
/*      */ 
/*      */     static final String FN_EXCEPTION = "ex";
/*      */     
/*      */ 
/*      */     static final String FN_CANCELLATION = "ca";
/*      */     
/*      */ 
/*      */     protected List<Recurrence.IException> mExceptions;
/*      */     
/*      */ 
/*      */ 
/*      */     public RecurrenceRule(ParsedDateTime dtstart, ParsedDuration duration, InviteInfo invId, List<Recurrence.IRecurrence> addRules, List<Recurrence.IRecurrence> subtractRules)
/*      */     {
/* 1391 */       super(duration, invId, addRules, subtractRules);
/* 1392 */       this.mExceptions = new ArrayList();
/*      */     }
/*      */     
/*      */ 
/*      */     public RecurrenceRule(ParsedDateTime dtstart, ParsedDuration duration, InviteInfo invId)
/*      */     {
/* 1398 */       super(duration, invId);
/* 1399 */       this.mExceptions = new ArrayList();
/*      */     }
/*      */     
/*      */     public int getType() {
/* 1403 */       return 1;
/*      */     }
/*      */     
/*      */     public void setInviteId(InviteInfo invId) {
/* 1407 */       super.setInviteId(invId);
/* 1408 */       assert (this.mExceptions.size() == 0);
/*      */     }
/*      */     
/*      */     public Iterator<Recurrence.IException> exceptionsIter() {
/* 1412 */       return this.mExceptions.iterator();
/*      */     }
/*      */     
/*      */     public RecurrenceRule(Metadata meta, TimeZoneMap tzmap) throws ServiceException, ParseException
/*      */     {
/* 1417 */       super(tzmap);
/*      */       
/* 1419 */       int numEx = (int)meta.getLong("numEx");
/* 1420 */       this.mExceptions = new ArrayList(numEx);
/*      */       
/* 1422 */       for (int i = 0; i < numEx; i++) {
/* 1423 */         if (meta.containsKey("ex" + i)) {
/* 1424 */           this.mExceptions.add(i, new Recurrence.ExceptionRule(meta.getMap("ex" + i), tzmap));
/* 1425 */         } else if (meta.containsKey("ca" + i)) {
/* 1426 */           this.mExceptions.add(i, new Recurrence.CancellationRule(meta.getMap("ca" + i), tzmap));
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */     public Element toXml(Element parent)
/*      */     {
/* 1433 */       for (Iterator iter = this.mExceptions.iterator(); iter.hasNext();) {
/* 1434 */         Recurrence.IException cur = (Recurrence.IException)iter.next();
/* 1435 */         cur.toXml(parent);
/*      */       }
/* 1437 */       super.toXml(parent);
/*      */       
/* 1439 */       return parent;
/*      */     }
/*      */     
/*      */     public void addException(Recurrence.IException rule)
/*      */     {
/* 1444 */       this.mExceptions.add(rule);
/*      */     }
/*      */     
/*      */     public List<CalendarItem.Instance> expandInstances(int calItemId, long start, long end) throws ServiceException
/*      */     {
/* 1449 */       long startAdjusted = start;
/* 1450 */       long endAdjusted = end;
/*      */       
/* 1452 */       for (Recurrence.IException except : this.mExceptions) {
/* 1453 */         if (except != null) {
/* 1454 */           RecurId rid = except.getRecurId();
/* 1455 */           if (rid != null) {
/* 1456 */             ParsedDateTime dt = rid.getDt();
/* 1457 */             if (dt != null) {
/* 1458 */               long recurIdTime = dt.getUtcTime();
/* 1459 */               ParsedDateTime st = except.getStartTime();
/* 1460 */               if (st != null) {
/* 1461 */                 long stTime = st.getUtcTime();
/* 1462 */                 if ((stTime >= start) && (stTime < end)) {
/* 1463 */                   if (recurIdTime < startAdjusted) {
/* 1464 */                     startAdjusted = recurIdTime;
/* 1465 */                   } else if (recurIdTime > endAdjusted)
/* 1466 */                     endAdjusted = recurIdTime + 1L;
/*      */                 }
/*      */               }
/* 1469 */               if (end < Long.MAX_VALUE) {
/* 1470 */                 ParsedDateTime et = except.getEndTime();
/* 1471 */                 if (et != null) {
/* 1472 */                   long etTime = et.getUtcTime();
/* 1473 */                   if ((etTime > start) && (etTime <= end)) {
/* 1474 */                     if (recurIdTime < startAdjusted) {
/* 1475 */                       startAdjusted = recurIdTime;
/* 1476 */                     } else if (recurIdTime > endAdjusted) {
/* 1477 */                       endAdjusted = recurIdTime + 1L;
/*      */                     }
/*      */                   }
/*      */                 }
/*      */               }
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/* 1487 */       List<CalendarItem.Instance> stdInstances = super.expandInstances(calItemId, startAdjusted, endAdjusted);
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 1492 */       for (Iterator<CalendarItem.Instance> iter = stdInstances.iterator(); iter.hasNext();) {
/* 1493 */         inst = (CalendarItem.Instance)iter.next();
/* 1494 */         if (inst != null) {
/* 1495 */           if ((inst.getEnd() < start) || (inst.getStart() >= end))
/*      */           {
/* 1497 */             iter.remove();
/*      */           } else {
/* 1499 */             for (Recurrence.IException except : this.mExceptions) {
/* 1500 */               if (except != null) {
/* 1501 */                 long instStart = inst.getStart();
/* 1502 */                 if (inst.isAllDay())
/*      */                 {
/* 1504 */                   RecurId eRid = except.getRecurId();
/* 1505 */                   if ((eRid != null) && (eRid.getDt() != null)) {
/* 1506 */                     long eOffset = eRid.getDt().getOffset();
/* 1507 */                     long iOffset = inst.getStartTzOffset();
/* 1508 */                     if (iOffset != eOffset)
/* 1509 */                       instStart += iOffset - eOffset;
/*      */                   }
/*      */                 }
/* 1512 */                 if (except.matches(instStart)) {
/* 1513 */                   iter.remove();
/* 1514 */                   break;
/*      */                 }
/*      */               }
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */       CalendarItem.Instance inst;
/* 1523 */       List<List<CalendarItem.Instance>> exceptionInstancesList = new ArrayList();
/* 1524 */       for (Recurrence.IException except : this.mExceptions) {
/* 1525 */         if (except != null) {
/* 1526 */           List<CalendarItem.Instance> instances = except.expandInstances(calItemId, startAdjusted, endAdjusted);
/*      */           
/* 1528 */           for (Iterator<CalendarItem.Instance> iter = instances.iterator(); iter.hasNext();) {
/* 1529 */             CalendarItem.Instance inst = (CalendarItem.Instance)iter.next();
/* 1530 */             if (inst != null) {
/* 1531 */               long st = inst.getStart();
/* 1532 */               long et = inst.getEnd();
/* 1533 */               if ((et < start) || (st >= end))
/* 1534 */                 iter.remove();
/*      */             }
/*      */           }
/* 1537 */           if (!instances.isEmpty()) {
/* 1538 */             exceptionInstancesList.add(instances);
/*      */           }
/*      */         }
/*      */       }
/*      */       List<CalendarItem.Instance> toRet;
/*      */       List<CalendarItem.Instance> toRet;
/* 1544 */       if (exceptionInstancesList.isEmpty()) {
/* 1545 */         toRet = stdInstances;
/*      */       } else {
/* 1547 */         toRet = new ArrayList();
/* 1548 */         List<CalendarItem.Instance>[] toAdd = new List[exceptionInstancesList.size() + 1];
/* 1549 */         toAdd[0] = stdInstances;
/* 1550 */         int offset = 1;
/* 1551 */         for (List<CalendarItem.Instance> except : exceptionInstancesList) {
/* 1552 */           toAdd[(offset++)] = except;
/*      */         }
/* 1554 */         ListUtil.mergeSortedLists(toRet, toAdd, true);
/*      */       }
/*      */       
/* 1557 */       return toRet;
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/* 1562 */       StringBuffer toRet = new StringBuffer();
/*      */       
/* 1564 */       toRet.append("RECUR(").append(super.toString());
/* 1565 */       for (Iterator iter = this.mExceptions.iterator(); iter.hasNext();) {
/* 1566 */         Recurrence.IException ex = (Recurrence.IException)iter.next();
/* 1567 */         toRet.append("\n\t\t").append(ex.toString());
/*      */       }
/* 1569 */       toRet.append(")");
/*      */       
/* 1571 */       return toRet.toString();
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public Metadata encodeMetadata()
/*      */     {
/* 1582 */       Metadata meta = super.encodeMetadata();
/*      */       
/* 1584 */       meta.put("t", Integer.toString(4));
/* 1585 */       meta.put("numEx", Integer.toString(this.mExceptions.size()));
/* 1586 */       for (int i = 0; i < this.mExceptions.size(); i++) {
/* 1587 */         Recurrence.IException cur = (Recurrence.IException)this.mExceptions.get(i);
/* 1588 */         if ((cur instanceof Recurrence.ExceptionRule)) {
/* 1589 */           meta.put("ex" + i, cur.encodeMetadata());
/*      */         } else {
/* 1591 */           meta.put("ca" + i, cur.encodeMetadata());
/*      */         }
/*      */       }
/* 1594 */       return meta;
/*      */     }
/*      */     
/*      */     private RecurrenceRule(RecurrenceRule other) {
/* 1598 */       super(other.mDuration == null ? null : (ParsedDuration)other.mDuration.clone(), other.mAddRules == null ? null : (Recurrence.MultiRuleSorter)other.mAddRules.clone(), other.mSubtractRules == null ? null : (Recurrence.MultiRuleSorter)other.mSubtractRules.clone(), other.mInvId == null ? null : (InviteInfo)other.mInvId.clone());
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 1603 */       this.mExceptions = new ArrayList();
/* 1604 */       for (Iterator iter = other.mExceptions.iterator(); iter.hasNext();) {
/* 1605 */         Recurrence.IException cur = (Recurrence.IException)iter.next();
/* 1606 */         this.mExceptions.add((Recurrence.IException)cur.clone());
/*      */       }
/*      */     }
/*      */     
/*      */     public Object clone()
/*      */     {
/* 1612 */       return new RecurrenceRule(this);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public static List<CalendarItem.Instance> expandInstances(IRecurrence recur, int calItemId, long start, long end)
/*      */     throws ServiceException
/*      */   {
/* 1621 */     List<CalendarItem.Instance> list = recur.expandInstances(calItemId, start, end);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/* 1626 */     List<CalendarItem.Instance> toRet = new ArrayList(list.size());
/* 1627 */     CalendarItem.Instance prev = null;
/* 1628 */     for (CalendarItem.Instance inst : list) {
/* 1629 */       if (prev == null) {
/* 1630 */         prev = inst;
/* 1631 */       } else if (inst != null) {
/* 1632 */         if (inst.sameTime(prev))
/*      */         {
/*      */ 
/* 1635 */           if (!inst.fromRdate()) {
/* 1636 */             prev = inst;
/*      */           }
/*      */         }
/*      */         else {
/* 1640 */           toRet.add(prev);
/* 1641 */           prev = inst;
/*      */         }
/*      */       }
/*      */     }
/* 1645 */     if (prev != null)
/* 1646 */       toRet.add(prev);
/* 1647 */     return toRet;
/*      */   }
/*      */   
/*      */   public static Set<String> getReferencedTZIDs(IRecurrence recur)
/*      */   {
/* 1652 */     Set<String> tzids = new HashSet();
/*      */     
/* 1654 */     for (Iterator iter = recur.addRulesIterator(); (iter != null) && (iter.hasNext());) {
/* 1655 */       IRecurrence cur = (IRecurrence)iter.next();
/* 1656 */       if (cur.getType() == 6) {
/* 1657 */         SingleDates sd = (SingleDates)cur;
/* 1658 */         RdateExdate rdate = sd.getRdateExdate();
/* 1659 */         ICalTimeZone tz = rdate.getTimeZone();
/* 1660 */         if (tz != null) {
/* 1661 */           tzids.add(tz.getID());
/*      */         }
/*      */       }
/*      */     }
/* 1665 */     for (Iterator iter = recur.subRulesIterator(); (iter != null) && (iter.hasNext());) {
/* 1666 */       IRecurrence cur = (IRecurrence)iter.next();
/* 1667 */       if (cur.getType() == 6) {
/* 1668 */         SingleDates sd = (SingleDates)cur;
/* 1669 */         RdateExdate exdate = sd.getRdateExdate();
/* 1670 */         ICalTimeZone tz = exdate.getTimeZone();
/* 1671 */         if (tz != null) {
/* 1672 */           tzids.add(tz.getID());
/*      */         }
/*      */       }
/*      */     }
/* 1676 */     ParsedDateTime recurStart = recur.getStartTime();
/* 1677 */     if (recurStart != null) {
/* 1678 */       ICalTimeZone tz = recurStart.getTimeZone();
/* 1679 */       if (tz != null) {
/* 1680 */         tzids.add(tz.getID());
/*      */       }
/*      */     }
/* 1683 */     return tzids;
/*      */   }
/*      */   
/*      */ 
/*      */   public static boolean sameSeriesRules(IRecurrence r1, IRecurrence r2)
/*      */   {
/* 1689 */     SimpleRepeatingRule rule1 = null;SimpleRepeatingRule rule2 = null;
/* 1690 */     for (Iterator iter1 = r1.addRulesIterator(); iter1.hasNext();) {
/* 1691 */       Object obj = iter1.next();
/* 1692 */       if (((obj instanceof SimpleRepeatingRule)) && (rule1 == null)) {
/* 1693 */         rule1 = (SimpleRepeatingRule)obj;
/* 1694 */         break;
/*      */       }
/*      */     }
/* 1697 */     for (Iterator iter2 = r2.addRulesIterator(); iter2.hasNext();) {
/* 1698 */       Object obj = iter2.next();
/* 1699 */       if (((obj instanceof SimpleRepeatingRule)) && (rule2 == null)) {
/* 1700 */         rule2 = (SimpleRepeatingRule)obj;
/* 1701 */         break;
/*      */       }
/*      */     }
/* 1704 */     if ((rule1 != null) && (rule2 != null)) {
/* 1705 */       return StringUtil.equal(rule1.toString(), rule2.toString());
/*      */     }
/* 1707 */     return rule1 == rule2;
/*      */   }
/*      */   
/*      */   public static void main(String[] args) throws Exception
/*      */   {
/* 1712 */     ICalTimeZone pacific = new ICalTimeZone("America/Los_Angeles", -28800000, "16010101T020000", "FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=11;BYDAY=1SU", "PST", -25200000, "16010101T020000", "FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=2SU", "PDT");
/*      */     
/*      */ 
/*      */ 
/* 1716 */     TimeZoneMap tzmap = new TimeZoneMap(pacific);
/* 1717 */     String str = "TZID=\"" + pacific.getID() + "\":20090105T120000";
/* 1718 */     ParsedDateTime dtStart = ParsedDateTime.parse(str, tzmap);
/* 1719 */     ParsedDuration duration = ParsedDuration.parse("PT1H");
/*      */     
/* 1721 */     List<IRecurrence> addRules = new ArrayList();
/* 1722 */     List<IRecurrence> subRules = new ArrayList();
/*      */     
/*      */ 
/* 1725 */     ZRecur rule = new ZRecur("FREQ=WEEKLY;INTERVAL=1", tzmap);
/* 1726 */     addRules.add(new SimpleRepeatingRule(dtStart, duration, rule, null));
/*      */     
/*      */ 
/* 1729 */     RdateExdate rdate = new RdateExdate(ZCalendar.ICalTok.RDATE, pacific);
/* 1730 */     str = "TZID=\"" + pacific.getID() + "\":20090106T120000";
/* 1731 */     ParsedDateTime rd1 = ParsedDateTime.parse(str, tzmap);
/* 1732 */     rdate.addValue(rd1);
/* 1733 */     str = "TZID=\"" + pacific.getID() + "\":20090107T120000";
/* 1734 */     ParsedDateTime rd2 = ParsedDateTime.parse(str, tzmap);
/* 1735 */     rdate.addValue(rd2);
/* 1736 */     addRules.add(new SingleDates(rdate, duration));
/*      */     
/*      */ 
/* 1739 */     str = "TZID=\"" + pacific.getID() + "\":20090216T120000";
/* 1740 */     ParsedDateTime ridDtModify1 = ParsedDateTime.parse(str, tzmap);
/* 1741 */     RecurId ridModify1 = new RecurId(ridDtModify1, RecurId.RANGE_NONE);
/* 1742 */     str = "TZID=\"" + pacific.getID() + "\":20090216T130000";
/* 1743 */     ParsedDateTime dtStartModify1 = ParsedDateTime.parse(str, tzmap);
/* 1744 */     ParsedDuration durModify1 = ParsedDuration.parse("PT2H");
/* 1745 */     ExceptionRule modify1 = new ExceptionRule(ridModify1, dtStartModify1, durModify1, null);
/*      */     
/*      */ 
/* 1748 */     str = "TZID=\"" + pacific.getID() + "\":20090119T120000";
/* 1749 */     ParsedDateTime dtCancel1 = ParsedDateTime.parse(str, tzmap);
/* 1750 */     RecurId ridCancel1 = new RecurId(dtCancel1, RecurId.RANGE_NONE);
/* 1751 */     CancellationRule cancel1 = new CancellationRule(ridCancel1);
/*      */     
/*      */ 
/* 1754 */     RdateExdate exdate = new RdateExdate(ZCalendar.ICalTok.EXDATE, pacific);
/* 1755 */     str = "TZID=\"" + pacific.getID() + "\":20090209T120000";
/* 1756 */     ParsedDateTime ex1 = ParsedDateTime.parse(str, tzmap);
/* 1757 */     exdate.addValue(ex1);
/* 1758 */     SingleDates exdateRule = new SingleDates(exdate, duration);
/* 1759 */     subRules.add(exdateRule);
/*      */     
/* 1761 */     RecurrenceRule recurrence = new RecurrenceRule(dtStart, duration, null, addRules, subRules);
/* 1762 */     recurrence.addException(modify1);
/* 1763 */     recurrence.addException(cancel1);
/*      */     
/*      */ 
/* 1766 */     Calendar startCal = new GregorianCalendar(pacific);
/* 1767 */     startCal.clear();
/* 1768 */     startCal.set(2009, 0, 1, 0, 0, 0);
/* 1769 */     Calendar endCal = (Calendar)startCal.clone();
/* 1770 */     endCal.add(1, 1);
/*      */     
/* 1772 */     List<CalendarItem.Instance> instances = recurrence.expandInstances(-1, startCal.getTimeInMillis(), Long.MAX_VALUE);
/* 1773 */     for (CalendarItem.Instance inst : instances) {
/* 1774 */       System.out.println(inst);
/*      */     }
/* 1776 */     System.out.println("Got " + instances.size() + " instances");
/*      */   }
/*      */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mailbox/calendar/Recurrence.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */